home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- /*------------------------------------------------------------------------------
- *
- * @(#) - Oort - Host validation routines.
- *
- * $Id: validate.c,v 1.2 1994/01/28 00:22:16 mtj Exp $
- *
- * Chris Fouts - May, 1993.
- *
- *----------------------------------------------------------------------------*/
- #include <stdio.h>
- #include <stdarg.h>
- #include <malloc.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netdb.h>
- #include <bstring.h>
- #include <string.h>
- #include <arpa/inet.h>
- #include <time.h>
- #include <sys/time.h>
-
- #include <X11/Intrinsic.h>
-
- #include "oort.h"
- #include "gameio.h"
- #include "validate.h"
-
- #define MAX_DROPS 2
- #define MAX_QUITS 3
- #define MAX_ACKS 20
-
- #define NG_STEADY_CENSUS_RATE 400 /* tenths o' seconds */
- #define NG_UNSTEADY_CENSUS_RATE 40 /* tenths o' seconds */
- #define NG_NEW_DEADLINE_TIME 50 /* seconds */
- #define NG_OLD_DEADLINE_TIME 120 /* seconds */
- #define NG_WEEDING_TIME 15 /* seconds */
- #define NG_DROPPING_DELTA -30 /* seconds */
-
- #define NG_VALID_UNKNOWN 0
- #define NG_VALID 1
- #define NG_INVALID 2
- #define NG_DROPPED 3
- #define NG_VALID_QUIT 4
-
- struct ngHost {
- long id ;
- short agrees ;
- short drops ;
- short quits ;
- short acks ;
- short valid ;
- short last_valid ;
- struct ngHost *next ;
- } ;
-
- struct ngCensusList {
- struct ngCensus census ;
- struct ngCensusList *next ;
- } ;
-
- /* BEGIN PROTOTYPES -S validate.c */
- static struct ngHost * addHost( long hostId ) ;
- static void addToTime( struct timeval *dst, long secs,
- long usecs ) ;
- static int compareCensus( struct ngCensus *input ) ;
- static void copyBytes( void *src, void *dst, long n ) ;
- static void copyTime( struct timeval *dst, struct timeval *src ) ;
- static void doWeeding( void ) ;
- static long elapsedSecTenths( struct timeval *bufThen,
- struct timeval *bufNow ) ;
- static struct ngHost * findHost( long hostId ) ;
- static int findHostInMyCensusList( long id ) ;
- static void generateCensusChecksum( void ) ;
- static char * ngPrintTimeHundreths( struct timeval *t ) ;
- static void resetDeadlines( int except ) ;
- static void sendAcknowledgement( long hostId ) ;
- static void setTime( struct timeval *dst, struct timeval *src,
- long secs, long usecs ) ;
- static void showHostValidity( struct ngHost *host ) ;
- /* END PROTOTYPES -S validate.c */
-
-
- static long selfId = 0 ;
- static unsigned short selfKey = 0 ;
- static char *selfName ;
- static ngMagic dropMagic ;
- static ngMagic invalidateMagic ;
- static ngMagic censusMagic ;
- static ngMagic ackMagic ;
- static ngMagic quitMagic ;
- static char *ngLogFile = NULL ;
-
- static struct ngHost *firstHost = NULL ;
- static unsigned short gameKey = 0 ;
- static struct timeval last_census_sent ;
- static long timeBetweenCensusPosts = 0 ;
- static Boolean needToSendCensus ;
- static Boolean needToDoWeeding = FALSE ;
- static struct timeval weedTime ;
- static struct ngCensusList myCensus ;
- extern unsigned int numberPlayers ;
-
- struct timeval start_up_time ;
- struct timeval currentTime ;
- struct timeval deadline[MAXPLAYERS] ;
-
-
- /*------------------------------------------------------------------------------
- * Inform validation routines of name and id.
- *----------------------------------------------------------------------------*/
- void
- ngInit(
- long id,
- unsigned short key,
- char *name,
- ngMagic drop,
- ngMagic invalidate,
- ngMagic census,
- ngMagic ack,
- ngMagic quit,
- char *logFile
- )
- {
- selfId = id ;
- selfKey = key ;
- selfName = strdup( name ) ;
- dropMagic = drop ;
- invalidateMagic = invalidate ;
- censusMagic = census ;
- ackMagic = ack ;
- quitMagic = quit ;
- ngLogFile = logFile ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Called *only* when an ACKNOWLEDGEMENT packet is received (or in view-only
- * mode).
- *---------------------------------------------------------------------------*/
- int
- ngValidKeyedHost(
- long hostId,
- unsigned short key
- )
- {
- struct ngHost *host ;
-
- if( key != gameKey )
- {
- return( 0 ) ;
- }
-
- if( ( host = findHost( hostId ) ) == NULL )
- {
- if( ( host = addHost( hostId ) ) == NULL )
- {
- perror( "validKeyedHost" ) ;
- endProgram( 1 ) ;
- }
- }
-
- if( host->valid == NG_VALID_UNKNOWN )
- {
- host->valid = NG_VALID ;
- ngDprintf( "%s: acknowledged by %s\n",
- ngPrintTime(), ngHostNameFromId( hostId ) ) ;
- }
-
- /*
- * If host had dropped me, it's now receiving my packets, so send an
- * ACK packet so it will know I see it and add me to its game.
- */
- else if( host->valid == NG_DROPPED )
- {
- host->valid = NG_VALID ;
- sendAcknowledgement( hostId ) ;
- ngDprintf( "%s: re-acknowledged by %s (had dropped me)\n",
- ngPrintTime(), ngHostNameFromId( hostId ) ) ;
- }
-
- return( host->valid == NG_VALID ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Returns TRUE if a host is valid.
- *----------------------------------------------------------------------------*/
- int
- ngValidHost(
- long hostId
- )
- {
- struct ngHost *host ;
-
- if( ( host = findHost( hostId ) ) == NULL )
- {
- return( 0 ) ;
- }
-
- /*
- * If host had quit, he has started back up again, so reset its status.
- */
- if( host->valid == NG_VALID_QUIT ) {
- host->valid = NG_VALID_UNKNOWN ;
- ngDprintf( "%s: receiving from %s again (had quit)\n",
- ngPrintTime(), ngHostNameFromId( hostId ) ) ;
- }
-
- return( host->valid == NG_VALID ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Find a host within the host list.
- *----------------------------------------------------------------------------*/
- static struct ngHost *
- findHost(
- long hostId
- )
- {
- struct ngHost *host = firstHost ;
-
- while( host != NULL )
- {
- if( host->id == hostId )
- {
- return( host ) ;
- }
- else
- {
- host = host->next ;
- }
- }
-
- return( host ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Add a host to the host list.
- *----------------------------------------------------------------------------*/
- static struct ngHost *
- addHost(
- long hostId
- )
- {
- struct ngHost *host = firstHost ;
- struct ngHost *prev = NULL ;
-
- while( host != NULL )
- {
- prev = host ;
- host = host->next ;
- }
-
- if( ( host = (struct ngHost *)malloc( sizeof( struct ngHost ) ) ) !=
- NULL )
- {
- host->id = hostId ;
- host->agrees = 0 ;
- host->drops = 0 ;
- host->quits = 0 ;
- host->acks = 0 ;
- host->valid = NG_VALID_UNKNOWN ;
- host->last_valid = NG_VALID_UNKNOWN ;
- host->next = NULL ;
- if( firstHost == NULL )
- {
- firstHost = host ;
- }
- ngDprintf( "%s: started receiving from %s\n",
- ngPrintTime(), ngHostNameFromId( hostId ) ) ;
- }
-
- if( prev != NULL )
- {
- prev->next = host ;
- }
-
- return( host ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Drop a host when I haven't received any packets in a while from it.
- *---------------------------------------------------------------------------*/
- void
- ngDropHost(
- long hostId
- )
- {
- struct ngHost *host ;
- struct ngAck invalid ;
-
- if( ( host = findHost( hostId ) ) == NULL )
- {
- return ;
- }
- host->drops += 1 ;
-
- if( host->drops > MAX_DROPS )
- {
- ngInvalidateHost( hostId ) ;
- }
- else
- {
- /*
- * Notify host of being dropped.
- */
- invalid.magic = dropMagic ;
- invalid.id = selfId ;
- invalid.ackId = hostId ;
- invalid.key = gameKey ;
- sendOut( &invalid, sizeof( invalid ) ) ;
- #if defined( NETDEBUGGER )
- post_new_message( 0, 0, "sent drop packet to %c", 'a' + hostId ) ;
- #endif /* defined( NETDEBUGGER ) */
-
- /*
- * Reset the host so that when I start receiving packets from it
- * again, I'll acknowledge it.
- */
- host->valid = NG_VALID_UNKNOWN ;
- host->acks = 0 ;
- ngDprintf( "%s: dropping %s from game (stopped getting "
- "packets)\n", ngPrintTime(),
- ngHostNameFromId( hostId ) ) ;
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Remove a host from our census list.
- *----------------------------------------------------------------------------*/
- void
- ngRemoveHostFromCensus(
- long id
- )
- {
- int i ;
- int n ;
- struct ngCensusList *next = myCensus.next ;
- struct ngCensusList *prev = &myCensus ;
-
- n = findHostInMyCensusList( id ) ;
-
- while( next && next->census.id != id ) {
- prev = next ;
- next = next->next ;
- }
-
- if( n < 0 || next == NULL ) {
- return ;
- }
-
- prev->next = next->next ;
-
- free( next ) ;
-
- myCensus.census.nPlayers-- ;
-
- copyBytes( &(myCensus.census.list[n+1]), &(myCensus.census.list[n]),
- (myCensus.census.nPlayers - n) *
- sizeof( myCensus.census.list[0] ) );
-
- generateCensusChecksum() ;
-
- needToSendCensus = TRUE ;
-
- i = findPlayer( id ) ;
- for( n = i ; n < numberPlayers ; n++ )
- {
- deadline[n] = deadline[n+1] ;
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Print out the time.
- *----------------------------------------------------------------------------*/
- char *
- ngPrintTime(
- void
- )
- {
- static char timestr[64] ;
- time_t clock_val ;
-
- clock_val = time( NULL ) ;
-
- cftime( timestr, "%r", &clock_val ) ;
-
- return( timestr ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Returns non-zero if the maximum number of acknowledgement packets have
- * not been sent.
- *----------------------------------------------------------------------------*/
- void
- ngAcknowledge(
- long hostId,
- unsigned short key
- )
- {
- struct ngHost *host ;
-
- if( key != gameKey )
- {
- return ;
- }
-
- if( ( host = findHost( hostId ) ) == NULL )
- {
- if( ( host = addHost( hostId ) ) == NULL )
- {
- perror( "should_acknowledge" ) ;
- endProgram( 1 ) ;
- }
- }
-
- if( host->acks < MAX_ACKS && host->valid == NG_VALID_UNKNOWN )
- {
- host->acks++ ;
- if( host->acks == 1 )
- {
- ngDprintf( "%s: should acknowledge %s.\n",
- ngPrintTime(), ngHostNameFromId( hostId ) );
- }
-
- sendAcknowledgement( hostId ) ;
- }
-
- return ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Send out an acknowledgement packet.
- *----------------------------------------------------------------------------*/
- static void
- sendAcknowledgement(
- long hostId
- )
- {
- struct ngAck ack ;
-
- ack.magic = ackMagic ;
- ack.id = selfId ;
- ack.ackId = hostId ;
- ack.key = selfKey ;
- sendOut( &ack, sizeof( ack ) ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Remove a host from the host list.
- *----------------------------------------------------------------------------*/
- void
- ngRemoveHost(
- long hostId
- )
- {
- struct ngHost *host = firstHost ;
- struct ngHost *prev = NULL ;
-
- while( host != NULL && host->id != hostId )
- {
- prev = host ;
- host = host->next ;
- }
-
- if( host == NULL )
- return ;
-
- if( host->id == hostId )
- {
- /*
- * If prev == NULL, this means we're removing the first host.
- * Set the firstHost to point to the next host.
- */
- if( prev == NULL )
- {
- firstHost = host->next ;
- }
- /*
- * We're past the first host, so link up the previous one to
- * the next one.
- */
- else
- {
- prev->next = host->next ;
- }
- free( host ) ;
- }
-
- return ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Note that a invalid host quit.
- *---------------------------------------------------------------------------*/
- void
- ngQuitHost(
- long hostId
- )
- {
- struct ngHost *host ;
- struct ngAck invalid ;
-
- if( ( host = findHost( hostId ) ) == NULL )
- {
- return ;
- }
-
- if( host->valid != NG_VALID_QUIT && host->quits < MAX_QUITS )
- {
- host->quits += 1 ;
- host->last_valid = host->valid ;
- host->valid = NG_VALID_QUIT ;
- host->acks = 0 ;
- ngDprintf( "%s: %s quit\n", ngPrintTime(),
- ngHostNameFromId( hostId ) ) ;
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * I've been dropped by a host, so indicate status with that host so that I
- * can know when it starts receiving me again.
- *---------------------------------------------------------------------------*/
- void
- ngDroppedByHost(
- long hostId
- )
- {
- struct ngHost *host ;
-
- if( ( host = findHost( hostId ) ) != NULL )
- {
- host->valid = NG_DROPPED ;
- ngDprintf( "%s: removing %s from game (dropped by him)\n",
- ngPrintTime(), ngHostNameFromId( hostId ) ) ;
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Invalidate a host. This is permanent. Will ignore all future packets
- * from this host (until it quits).
- *---------------------------------------------------------------------------*/
- void
- ngInvalidateHost(
- long hostId
- )
- {
- int i ;
- int j ;
- struct ngHost *host ;
- struct ngAck invalid ;
- struct ngCensusList *cen ;
-
- if( ( host = findHost( hostId ) ) != NULL )
- {
- host->valid = NG_INVALID ;
-
- /*
- * Notify host of being invalidated.
- */
- invalid.magic = invalidateMagic ;
- invalid.id = selfId ;
- invalid.ackId = hostId ;
- invalid.key = gameKey ;
- sendOut( &invalid, sizeof( invalid ) ) ;
- if( ( cen = findHostCensus( hostId ) ) != NULL )
- {
- ngDprintf( "%s: %s invalidated --\n",
- ngPrintTime(), ngHostNameFromId( hostId ) ) ;
- ngDprintf( "\tHe sees %ld hosts while you see %ld.\n",
- cen->census.nPlayers,
- myCensus.census.nPlayers ) ;
- ngDprintf( "\tThe following hosts were seen by "
- "him:\n" ) ;
- for( i = 0 ; i < cen->census.nPlayers ; i++ )
- {
- if( cen->census.list[i] == selfId )
- {
- ngDprintf( "\t\t%s (valid - self)\n",
- ngHostNameFromId( cen->census.list[i]));
- }
- else
- {
- host = findHost( cen->census.list[i] ) ;
- if( host == NULL )
- {
- ngDprintf( "\t\t%s (do not see)"
- "\n", ngHostNameFromId(
- cen->census.list[i] ) );
- }
- else
- {
- showHostValidity( host ) ;
- }
- }
- }
- ngDprintf( "\tThe following hosts were seen by you but "
- "not validated by him:\n" ) ;
-
- j = 0 ;
- for( i = 0 ; i < myCensus.census.nPlayers ; i++ )
- {
- while( j < cen->census.nPlayers &&
- myCensus.census.list[i] >
- cen->census.list[j] )
- {
- j++ ;
- }
- if( j < cen->census.nPlayers &&
- myCensus.census.list[i] ==
- cen->census.list[j] )
- {
- j++ ;
- }
- else if( myCensus.census.list[i] != selfId )
- {
- ngDprintf( "\t\t%s\n",
- ngHostNameFromId(
- myCensus.census.list[i] ) ) ;
- }
- }
- ngDprintf( "end list for %s\n\n",
- ngHostNameFromId( hostId ) ) ;
- }
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Print out the valid of a host.
- *----------------------------------------------------------------------------*/
- static void
- showHostValidity(
- struct ngHost *host
- )
- {
-
- if( host->valid == NG_INVALID )
- {
- ngDprintf( "\t\t%s (invalidated)\n",
- ngHostNameFromId( host->id ) ) ;
- }
- else if( host->valid == NG_VALID_UNKNOWN )
- {
- if( host->drops )
- {
- ngDprintf( "\t\t%s (lost communication from)\n",
- ngHostNameFromId( host->id ) ) ;
- }
- else
- {
- ngDprintf( "\t\t%s (does not see me)\n",
- ngHostNameFromId( host->id ) ) ;
- }
- }
- else if( host->valid == NG_VALID_QUIT )
- {
- if( host->last_valid == NG_VALID_QUIT )
- {
- ngDprintf( "\t\t%s (thought had quit)\n",
- ngHostNameFromId( host->id ) ) ;
- }
- else
- {
- host->valid = host->last_valid ;
- showHostValidity( host ) ;
- host->valid = NG_VALID_QUIT ;
- }
- }
- else
- {
- ngDprintf( "\t\t%s (valid)\n",
- ngHostNameFromId( host->id ) ) ;
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Send quit packets.
- *----------------------------------------------------------------------------*/
- void
- ngSendQuitPacket(
- void
- )
- {
- struct ngAck ack ;
-
- ack.magic = quitMagic ;
- ack.id = selfId ;
- ack.ackId = selfId ;
- ack.key = selfKey ;
-
- /*
- * Send out 3 for good measure.
- */
- sendOut( &ack, sizeof( ack ) ) ;
- sendOut( &ack, sizeof( ack ) ) ;
- sendOut( &ack, sizeof( ack ) ) ;
-
- ngDprintf( "\n%s: quitting game\n", ngPrintTime() ) ;
- validationSummary() ;
-
- sleep( 1 ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Debug printf.
- *----------------------------------------------------------------------------*/
- void
- ngDprintf(
- char *fmt,
- ...
- )
- {
- va_list args ;
- static int status = 0 ;
- static FILE *debugOut ;
-
- if( status == -1 || ngLogFile == NULL )
- {
- return ;
- }
-
- if( strcmp( fmt, "end" ) == 0 )
- {
- if( status == 1 )
- {
- fclose( debugOut ) ;
- printf( "Summary of validations written to %s.\n",
- ngLogFile ) ;
- }
- return ;
- }
- else if( strcmp( fmt, "disable" ) == 0 )
- {
- status = -1 ;
- return ;
- }
-
- if( status == 0 )
- {
- if( ( debugOut = fopen( ngLogFile, "w" ) ) == NULL )
- {
- status = -1 ;
- return ;
- }
- else
- {
- status = 1 ;
- }
- }
-
- va_start( args, fmt ) ;
- vfprintf( debugOut, fmt, args ) ;
- va_end( args ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Register the game's key code.
- *----------------------------------------------------------------------------*/
- void
- ngRegisterKey(
- unsigned short key
- )
- {
- gameKey = key ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Generate the census checksum (both xor and summation) from the list of
- * hostid's in the census host list.
- *----------------------------------------------------------------------------*/
- static void
- generateCensusChecksum(
- void
- )
- {
- int i ;
-
- myCensus.census.chksum = 0 ;
- myCensus.census.chkxor = 0 ;
- for( i = 0 ; i < myCensus.census.nPlayers ; i++ )
- {
- myCensus.census.chksum = ( myCensus.census.chksum +
- ( myCensus.census.list[i] & 0x3fffffff ) ) &
- 0x3fffffff ;
- myCensus.census.chkxor ^= myCensus.census.list[i] ;
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Initialize the internal census packet.
- *----------------------------------------------------------------------------*/
- void
- ngInitCensusPacket(
- long id
- )
- {
- myCensus.census.magic = censusMagic ;
- myCensus.census.id = id ;
- myCensus.census.nPlayers = 1 ;
- myCensus.census.list[0] = id ;
- myCensus.next = NULL ;
- copyTime( &last_census_sent, ¤tTime ) ;
-
- setTime( &weedTime, ¤tTime, NG_WEEDING_TIME, 0 ) ;
- needToDoWeeding = FALSE ;
-
- generateCensusChecksum() ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Move bytes from one source to another, allowing for overlap
- *----------------------------------------------------------------------------*/
- static void
- copyBytes(
- void *src,
- void *dst,
- long n
- )
- {
- char *s ;
- char *d ;
-
- if( src > dst )
- {
- s = (char *)src ;
- d = (char *)dst ;
- while( n-- )
- *(d++) = *(s++) ;
- }
- else
- {
- s = (char *)src + n ;
- d = (char *)dst + n ;
- while( n-- )
- *(--d) = *(--s) ;
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Add a host to our census list.
- *----------------------------------------------------------------------------*/
- void
- ngAddHostToCensus(
- long id
- )
- {
- int n ;
- int i ;
- int insertPt ;
- static int first = 1 ;
- struct ngCensusList *next = myCensus.next ;
- struct ngCensusList *prev = &myCensus ;
-
- if( findHostInMyCensusList( id ) != -1 )
- {
- return ;
- }
-
- if( ( i = findPlayer( id ) ) == -1 )
- {
- return ;
- }
-
- n = (myCensus.census.nPlayers)++ ;
-
- while( next )
- {
- prev = next ;
- next = next->next ;
- }
-
- if( ( next = calloc( 1, sizeof( struct ngCensusList ) ) ) == NULL )
- {
- perror( "ngAddHostToCensus" ) ;
- endProgram( 1 ) ;
- }
-
- prev->next = next ;
-
- next->census.id = id ;
- next->census.nPlayers = 1 ;
- next->census.chksum = id ;
- next->census.chkxor = id ;
-
- insertPt = n ;
- while( insertPt && myCensus.census.list[insertPt-1] > id )
- insertPt-- ;
-
- copyBytes( &(myCensus.census.list[insertPt]),
- &(myCensus.census.list[insertPt+1]),
- ( n - insertPt ) * sizeof( myCensus.census.list[0] ) ) ;
-
- myCensus.census.list[insertPt] = id ;
-
- generateCensusChecksum() ;
-
- if( !first )
- {
- resetDeadlines( i ) ;
- }
- first = 0 ;
-
- setTime( &weedTime, ¤tTime, NG_WEEDING_TIME, 0 ) ;
- needToDoWeeding = TRUE ;
-
- setTime( &(deadline[i]), ¤tTime, NG_NEW_DEADLINE_TIME, 0 ) ;
- ngDprintf( "%s: added %s to game and census\n", ngPrintTime(),
- ngHostNameFromId( id ) ) ;
-
- needToSendCensus = TRUE ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Find a host in the linked list of census packets.
- *----------------------------------------------------------------------------*/
- struct ngCensusList *
- findHostCensus(
- long id
- )
- {
- struct ngCensusList *next = myCensus.next ;
-
- while( next && next->census.id != id )
- {
- next = next->next ;
- }
-
- return( next ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Locate a host within our census list.
- *----------------------------------------------------------------------------*/
- static int
- findHostInMyCensusList(
- long id
- )
- {
- int n ;
- int lo = 0 ;
- int hi = myCensus.census.nPlayers - 1 ;
- long *census_list = myCensus.census.list ;
-
- while( 1 )
- {
- n = ( lo + hi ) / 2 ;
- if( id == census_list[n] )
- {
- return( n ) ;
- }
- else if( id < census_list[n] )
- {
- hi = n - 1 ;
- }
- else
- {
- lo = n + 1 ;
- }
- if( lo > hi )
- {
- return( -1 ) ;
- }
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Compare a census packet with another.
- *----------------------------------------------------------------------------*/
- static int
- compareCensus(
- struct ngCensus *input
- )
- {
- return( ( input->nPlayers == myCensus.census.nPlayers ) &&
- ( input->chksum == myCensus.census.chksum ) &&
- ( input->chkxor == myCensus.census.chkxor ) ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Process a census packet.
- *----------------------------------------------------------------------------*/
- void processNgCensus(
- struct ngCensus *input
- )
- {
- int n ;
- int i ;
- struct ngCensusList *pcen ;
- struct ngHost *host ;
-
- if( ( n = findPlayer( input->id ) ) > 0 )
- {
- /*
- * Save the census packet.
- */
- if( ( pcen = findHostCensus( input->id ) ) == NULL )
- {
- #if defined( NETDEBUGGER )
- post_new_message( 0, 0, "could not find CENSUS for %c",
- 'a' + input->id ) ;
- #endif /* defined( NETDEBUGGER ) */
- return ;
- }
- else
- {
- copyBytes( input, &(pcen->census),
- sizeof( struct ngCensus ) ) ;
- }
- /*
- * Check if census matches up with SELF's census.
- */
- if( compareCensus( input ) )
- {
- /*
- * It matches, so set new deadline for player.
- */
- setTime( &(deadline[n]), ¤tTime,
- NG_OLD_DEADLINE_TIME, 0 ) ;
- if( ( host = findHost( input->id ) ) != NULL )
- {
- if( host->agrees == 0 )
- {
- ngDprintf( "%s: validation now matching"
- " from %s.\n", ngPrintTime(),
- ngHostNameFromId( host->id ) ) ;
- host->agrees = 1 ;
- }
- }
- }
- else
- {
- /*
- * No match. See if player's deadline has been
- * exceeded.
- */
- if( ( host = findHost( input->id ) ) != NULL )
- {
- if( host->agrees == 1 )
- {
- ngDprintf( "%s: validation no longer "
- "matches from %s.\n",
- ngPrintTime(),
- ngHostNameFromId( host->id ) ) ;
- host->agrees = 0 ;
- }
- }
- if( elapsedSecTenths( &(deadline[n]), ¤tTime )
- > 0 )
- {
- /*
- * Deadline passed, drop player.
- */
- ngInvalidateHost( input->id ) ;
- deletePlayer( n, "was invalidated" ) ;
- }
-
- /*
- * Set time between census broadcasts to a smaller
- * number since the census lists are in flux.
- */
- timeBetweenCensusPosts = NG_UNSTEADY_CENSUS_RATE ;
- }
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Check to see if we need to send a census packet.
- *----------------------------------------------------------------------------*/
- void
- checkToSendCensus(
- void
- )
- {
- long tenths ;
-
- if( needToDoWeeding &&
- elapsedSecTenths( &weedTime, ¤tTime ) > 0 )
- {
- doWeeding() ;
- needToDoWeeding = FALSE ;
- }
-
- if( needToSendCensus ||
- elapsedSecTenths( &last_census_sent, ¤tTime ) >
- timeBetweenCensusPosts )
- {
- needToSendCensus = FALSE ;
- sendOut( &(myCensus.census), sizeof( struct ngCensus ) ) ;
- copyTime( &last_census_sent, ¤tTime ) ;
- timeBetweenCensusPosts = NG_STEADY_CENSUS_RATE ;
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Reset all of the census deadlines except for the newest.
- *----------------------------------------------------------------------------*/
- static void
- resetDeadlines(
- int except
- )
- {
- int i ;
- long secs ;
- long tenths ;
-
- if( ( secs = elapsedSecTenths( &last_census_sent, ¤tTime ) ) <
- NG_OLD_DEADLINE_TIME * 10 )
- {
-
- tenths = secs % 10 ;
- secs /= 10 ;
-
- for( i = ENEMY ; i < numberPlayers ; i++ )
- {
- if( i != except )
- {
- setTime( &(deadline[i]), &(deadline[i]), secs,
- tenths ) ;
- }
- }
- }
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Print out a list of all non-valid hosts and a guess at why.
- *----------------------------------------------------------------------------*/
- void
- validationSummary( void )
- {
- struct ngHost *host = firstHost ;
-
- while( host )
- {
- switch( host->valid )
- {
-
- case NG_VALID_UNKNOWN :
- if( host->drops )
- {
- ngDprintf( "Lost communcation from host"
- " %s.\n",
- ngHostNameFromId( host->id ) ) ;
- }
- else
- {
- ngDprintf( "Host %s evidently could not"
- "receive my packets.\n",
- ngHostNameFromId( host->id ) ) ;
- }
- break ;
-
- case NG_VALID :
- ngDprintf( "Host %s was valid.\n",
- ngHostNameFromId( host->id ) ) ;
- break ;
-
- case NG_INVALID :
- break ;
-
- case NG_VALID_QUIT :
- ngDprintf( "Host %s has quit (validity "
- "unknown).\n",
- ngHostNameFromId( host->id ) ) ;
- break ;
-
- case NG_DROPPED :
- ngDprintf( "Host %s evidently stopped receiving"
- "my packets.\n",
- ngHostNameFromId( host->id ) ) ;
- break ;
-
- default :
- ngDprintf( "Odd validity for %s.\n",
- ngHostNameFromId( host->id ) ) ;
- break ;
- }
- host = host->next ;
- }
-
- ngDprintf( "end" ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Convert a `hostid' number to a string representing the host's name if
- * known, otherwise the IP address.
- *----------------------------------------------------------------------------*/
- char
- *ngHostNameFromId(
- long id
- )
- {
- struct in_addr addr ;
- struct hostent *hp ;
- static char buffer[256] ;
-
- addr.s_addr = id ;
- hp = gethostbyaddr( &addr, sizeof(addr), AF_INET ) ;
- if( hp )
- {
- sprintf( buffer, "%s (%s)", hp->h_name, inet_ntoa(addr) ) ;
- }
- else
- {
- sprintf( buffer, "%s", inet_ntoa(addr) ) ;
- }
-
- return( buffer ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Do initial weeding of host to try and join the largest group.
- *----------------------------------------------------------------------------*/
- static void
- doWeeding(
- void
- )
- {
- int i ;
- int j ;
- int n ;
- int total ;
- int best_total = 0 ;
- int least_seen ;
- int times_seen[MAXPLAYERS] ;
- struct ngCensusList *next = myCensus.next ;
- struct ngCensusList *prev = &myCensus ;
- struct ngCensusList *best ;
-
- #if defined( NETDEBUGGER )
- post_new_message( 0, 0, "%s doing initial weeding", ngPrintTime() ) ;
- #endif /* defined( NETDEBUGGER ) */
-
- /*
- * Go through all players in my census and mark as being seen once
- * (by me).
- */
- for( i = 0 ; i < myCensus.census.nPlayers ; i++ )
- {
- times_seen[i] = 1 ;
- }
-
- /*
- * Go through all other players and mark players according to how many
- * times they appear on other's censuses.
- */
- while( next )
- {
- total = 0 ;
- for( i = 0 ; i < next->census.nPlayers ; i++ )
- {
- /*
- * Check if host is on my census.
- */
- n = findHostInMyCensusList( next->census.list[i] ) ;
- /*
- * If host is in my census, increment total and mark
- * player.
- */
- if( n != -1 )
- {
- total++ ;
- times_seen[n] += 1 ;
- }
- }
- /*
- * Check number of census matches.
- */
- if( total > best_total )
- {
- best = next ;
- best_total = total ;
- }
- next = next->next ;
- }
-
- #if defined( NETDEBUGGER )
- for( i = 0 ; i < myCensus.census.nPlayers ; i++ )
- {
- post_new_message( 0, 0, "* * %c seen %d times",
- 'a' + myCensus.census.list[i], times_seen[i] ) ;
- }
- #endif /* defined( NETDEBUGGER ) */
-
- /*
- * If the best match is greater than zero...
- */
- if( best_total > 0 && best != NULL )
- {
-
- #if defined( NETDEBUGGER )
- post_new_message( 0, 0, "* * best total = %d/%d "
- "(player %c)", best_total, best->census.nPlayers,
- 'a' + best->census.id ) ;
- #endif /* defined( NETDEBUGGER ) */
-
- /*
- * Compare my census with the best match.
- */
- j = 0 ;
- least_seen = best_total + 1 ;
- for( i = 0 ; i < myCensus.census.nPlayers ; i++ )
- {
- /*
- * Find location in best census where my i-th census
- * entry should be.
- */
- while( j < best->census.nPlayers &&
- myCensus.census.list[i] > best->census.list[j] )
- {
- j++ ;
- }
- /*
- * If i-th entry is in best census, check for least
- * seen value.
- */
- if( j < best->census.nPlayers &&
- myCensus.census.list[i] == best->census.list[j])
- {
- if( times_seen[i] <= least_seen )
- {
- least_seen = times_seen[i] ;
- }
- j++ ;
- }
- /*
- * The i-th entry isn't in the best census, so shorten
- * it's deadline.
- */
- else
- {
- n = findPlayer( myCensus.census.list[i] ) ;
- if( n > 0 )
- {
- setTime( &(deadline[n]), &(deadline[n]),
- NG_DROPPING_DELTA, 0 ) ;
- #if defined( NETDEBUGGER )
- post_new_message( 0, 0, "* * "
- "should_drop %c (%s)",
- 'a' + myCensus.census.list[i],
- ngPrintTimeHundreths(
- &(deadline[n]) ) ) ;
- #endif /* defined( NETDEBUGGER ) */
- }
- }
- }
-
- #if defined( NETDEBUGGER )
- post_new_message( 0, 0, "* * least_seen = %d",
- least_seen ) ;
- #endif /* defined( NETDEBUGGER ) */
-
- /*
- * If some entry is seen less times than the best total, shorten
- * its deadline time.
- */
- if( least_seen < best_total )
- {
- for( i = 0 ; i < myCensus.census.nPlayers ; i++ )
- {
- if( times_seen[i] == least_seen )
- {
- /*
- * Decrease deadline.
- */
- n = findPlayer(
- myCensus.census.list[i] ) ;
- if( n > 0 )
- {
- setTime( &(deadline[n]),
- &(deadline[n]),
- NG_DROPPING_DELTA, 0 ) ;
- #if defined( NETDEBUGGER )
- post_new_message( 0, 0,
- "* * should_drop"
- " %c (%s)", 'a' +
- myCensus.census.list[i],
- ngPrintTimeHundreths(
- &(deadline[n]) ) ) ;
- #endif /* defined( NETDEBUGGER ) */
- }
- }
- }
- }
- }
-
- #if defined( NETDEBUGGER )
- post_new_message( 0, 0, "********** ending weeding" ) ;
- #endif /* defined( NETDEBUGGER ) */
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Print out the date.
- *----------------------------------------------------------------------------*/
- char *
- printDate(
- void
- )
- {
- static char datestr[64] ;
- time_t clock_val ;
-
- clock_val = time( NULL ) ;
-
- cftime( datestr, "%D", &clock_val ) ;
-
- return( datestr ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Print out the time with hundreths of seconds.
- *----------------------------------------------------------------------------*/
- static char *
- ngPrintTimeHundreths(
- struct timeval *t
- )
- {
- static char timestr[64] ;
- int i ;
- time_t secs ;
- long hsecs ;
-
- secs = t->tv_sec + t->tv_usec / 1000000 ;
- hsecs = ( t->tv_usec % 1000000 ) / 10000 ;
- cftime( timestr, "%I:%M:%S.00 %p", &secs ) ;
- i = strlen( timestr ) ;
-
- sprintf( timestr + 9, "%02d", hsecs ) ;
- timestr[11] = ' ' ;
-
- return( timestr ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Copy over a timeval structure.
- *----------------------------------------------------------------------------*/
- static void copyTime(
- struct timeval *dst,
- struct timeval *src
- )
- {
- bcopy( src, dst, sizeof( struct timeval ) ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Initialize a timeval structure.
- *----------------------------------------------------------------------------*/
- static void setTime(
- struct timeval *dst,
- struct timeval *src,
- long secs,
- long usecs
- )
- {
- copyTime( dst, src ) ;
- addToTime( dst, secs, usecs ) ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Add an offset to a timeval structure.
- *----------------------------------------------------------------------------*/
- static void
- addToTime(
- struct timeval *dst,
- long secs,
- long usecs
- )
- {
- dst->tv_usec += usecs ;
- dst->tv_sec += secs + ( dst->tv_usec / 1000000 ) ;
- dst->tv_usec %= 1000000 ;
- }
-
-
-
- /*------------------------------------------------------------------------------
- * Return the number of tenths of seconds elapsed since a specified time.
- *----------------------------------------------------------------------------*/
- static long
- elapsedSecTenths(
- struct timeval *bufThen,
- struct timeval *bufNow
- )
- {
- struct timeval tv ;
- struct timeval *now ;
- struct timeval *then = bufThen ;
- struct timezone tzp ;
-
- if( bufNow != NULL )
- {
- now = bufNow ;
- }
- else
- {
- now = &tv ;
- gettimeofday( now, &tzp ) ;
- }
-
- return( ( ( now->tv_sec - then->tv_sec ) * 10 +
- ( now->tv_usec - then->tv_usec ) / 100000 ) ) ;
- }
-
-
-
-